package cn.ly;

import org.I0Itec.zkclient.ZkClient;
import org.apache.zookeeper.data.Stat;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;

/**
 * 使用Zookeeper生成全局唯一ID
 * 方案一：通过持久顺序节点实现；
 * 方案二：通过节点版本号；
 */
public class TestID implements Runnable {

    //问题：在创建有序节点时，客户端需要加锁来保证它的序号是唯一不重复么。还有zk是如何保证多线程下节点的名称是唯一的啊
    //答：不需要。ZkServer自己会保证全局唯一。节点唯一原理是在：发送的请求是放到ConcurrentHashMap，而这个本身就是线程安全的
    private ZkClient zkClient = new ZkClient("127.0.0.1:2181");
    private static final String ID_NODE = "/id";
    private List<Object> list;
    public TestID(List<Object> list) {
        this.list = list;
    }

    //方式一：使用有序节点
    public String getId(){
        //【注意】：需要先在Zookeeper中创建其父类节点：/id
        //返回节点名称：0000000000、0000000001、0000000002、0000000003.....
        return zkClient.createEphemeralSequential(ID_NODE+"/","");
    }
    //方式二：版本号
    public int getVersion(){
        Stat stat =zkClient.writeDataReturnStat(ID_NODE,"",-1);
        return stat.getVersion();   // 返回版本号：1、2、3、4、5......
    }
    @Override
    public void run() {
        list.add(getId());  //方式一
//        list.add(getVersion());   //方式二
        countDownLatch.countDown();
    }

    static CountDownLatch countDownLatch = new CountDownLatch(100);
    public static void main(String[] args) throws InterruptedException {
        List<Object> list = new ArrayList<>();
        for(int i=0;i<100;i++){
            new Thread(new TestID(list)).run();
        }
        countDownLatch.await();
        list.forEach(a-> System.out.println(">>>>>>>>id:"+a));
    }

}
